//--------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

#include "dkbasic.h"
#include "dkterm.h"
#include "dkstatements.h"
#include "dkvariables.h"
#include "dkstring.h"
#include "dkexpression.h"
#include "dkprogram.h"
#include "dkinterpreter.h"
#include "dkevents.h"
#include "dktimer.h"
#include "dkfile_ps2kbd.h"
#include "dkvt100.h"

//--------------------------------------------------------------------
// note: statement handlers added here must also be added to the list in dkstatementtable.S
//--------------------------------------------------------------------


struct _dkfornext *dkfornextstack;
struct _dkwhilewend *dkwhilewendstack;
struct _dkgosub *dkgosubstack;



//--------------------------------------------------------------------
char *dkstatement_rem( char *line )
{
	return line+strlen(line);
}

//--------------------------------------------------------------------
char *dkstatement_let( char *line )
{
	char t[MAX_TOKEN_LENGTH+1];
	char t2[MAX_TOKEN_LENGTH+1];
	uint16_t nameflags;
	dkexpression *e;
	int numdims=0;
	uint16_t dims[DK_MAX_ARRAY_DIMS];


	line = dkgettoken( line, t );		// get first token in t (variable name)
	if( !isalpha( t[0] ) )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;
	}

	line = dkgetnameflags( line, &nameflags );
	
	if( nameflags & DKNAME_PAREN )
	{									// name has a parenthesis following it, treat it as an array
		e = dkgetfirstexpression( line );
		line = expstr;
		if( e )
		{
			dkexptoint(e);
			if( e->type != DKVAR_INTEGER )
			{
				if( !dkstatus )	
					dkstatus = DKSTATUS_SYNTAXERROR;
				dkexpfree(e);
				return NULL;
			}
			dims[numdims] = ((uint16_t *)e->data)[0];
			numdims++;
			dkexpfree(e);

			while( (e = dkgetnextexpression( expstr )) && numdims<DK_MAX_ARRAY_DIMS )
			{
				dkexptoint(e);
				if( e->type != DKVAR_INTEGER )
				{
					if( !dkstatus )	
						dkstatus = DKSTATUS_SYNTAXERROR;
					dkexpfree(e);
					return NULL;
				}
				dims[numdims] = ((uint16_t *)e->data)[0];
				numdims++;
				dkexpfree(e);				
			}
			line = expstr;
		}
	}			// numdims = # of dimensions, dims[] contains indexes for each dimension


	line = dkgettoken( line, t2 );		// get next token - should be '='
	if( t2[0]!='=' )
	{	
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;
	}

	e = expression( line );
	line = expstr;

	if( !e )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_MISSINGOPERAND;
		return line;
	}


	if(! ( (nameflags&DKNAME_INTEGER)|(nameflags&DKNAME_FLOATSINGLE)|(nameflags&DKNAME_FLOATDOUBLE)|(nameflags&DKNAME_STRING)|(nameflags&DKNAME_BYTE) ) )
		nameflags |= DKVAR_DEFAULT;		// set default		NOTE: this relies on DKVAR_xxx and DKNAME_xxxx being the same

	if( nameflags&DKNAME_INTEGER )
	{									// name specifies integer
		dkexptoint( e );
		if( e->type!=DKVAR_INTEGER )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_TYPEMISMATCH;
			return line;
		}

		if( numdims )
			dksetinarray( t, DKVAR_INTEGER|DKVAR_ARRAY, e->data, numdims, dims );
		else
			dksetvariable( t, DKVAR_INTEGER, e->data );
	}
	else if( nameflags&DKNAME_BYTE )
	{									// name specifies integer
		dkexptobyte( e );
		if( e->type!=DKVAR_BYTE )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_TYPEMISMATCH;
			return line;
		}

		if( numdims )
			dksetinarray( t, DKVAR_BYTE|DKVAR_ARRAY, e->data, numdims, dims );
		else
			dksetvariable( t, DKVAR_BYTE, e->data );
	}
	else if( nameflags&DKNAME_STRING )
	{									// name specifies string
		if( e->type == DKVAR_STRING )	// name=string, type=string
		{
			if( numdims )
				dksetinarray( t, DKVAR_STRING|DKVAR_ARRAY, e->data, numdims, dims );
			else
				dksetvariable( t, DKVAR_STRING, e->data );
		}
		else
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_TYPEMISMATCH;
			dkexpfree( e );
			return line;
		}
	}									
	else if( nameflags&DKNAME_FLOATSINGLE )	// name specifies floatsingle
	{									
		dkexptofloatsingle( e );
		if( e->type!=DKVAR_FLOATSINGLE )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_TYPEMISMATCH;
			return line;
		}

		if( numdims )
			dksetinarray( t, DKVAR_FLOATSINGLE|DKVAR_ARRAY, e->data, numdims, dims );
		else
			dksetvariable( t, DKVAR_FLOATSINGLE, e->data );
	}
	else if( nameflags&DKNAME_FLOATDOUBLE )	// name specifies floatdouble
	{									
		dkexptofloatsingle( e );
		if( e->type!=DKVAR_FLOATDOUBLE )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_TYPEMISMATCH;
			return line;
		}

		if( numdims )
			dksetinarray( t, DKVAR_FLOATDOUBLE|DKVAR_ARRAY, e->data, numdims, dims );
		else
			dksetvariable( t, DKVAR_FLOATDOUBLE, e->data );
	}


	dkexpfree( e );
	return line;
}



//--------------------------------------------------------------------
char *dkstatement_if( char *line )
{
	char t[MAX_TOKEN_LENGTH+1];
	dkexpression *e;
	char *lptr;
	char *thenptr=NULL;
	char *elseptr=NULL;
	char *prevptr=0;


	e = expression( line );				// get expression being tested
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					// syntax error - no expression
	}
/// check for 'then'
	lptr = line;
	while( lptr[0] )					// loop until end of line, or until "else" is found
	{
		prevptr = lptr;
		lptr = dkgettoken( lptr, t );
		strlwr( t );
		if( !strcmp_P( t, PSTR("else") ) )
		{
			thenptr = (char *)malloc( prevptr-line+1 );	// allocate space for string to hold copy of 'then' clause
			if( !thenptr )
			{
				dkstatus = DKSTATUS_OUTOFMEMORY;
				if( e )
					dkexpfree( e );
				return line;
			}
			strncpy( thenptr, line, prevptr-line );	// copy from immediately after expression until before 'else'
			thenptr[prevptr-line] = '\0';

			elseptr = lptr;					// elseptr points immediately after 'else'
			break;
		}
		else if( !strcmp_P( t, PSTR("if") ) )	// found another if - no else clause for current if statement
			break;
	}


	if( ((int16_t *)e->data)[0] )
	{										// expression is true, execute THEN clause
		if( elseptr )
			line = thenptr;					// if there's an else clause, interpret the copy made

		lptr = dkgettoken( line, t );		// get "THEN" or "GOTO"
		strlwr( t );
		if( !strcmp_P( t, PSTR("then") ) )
		{
	// check if line number immediately follows 'then'
			line = lptr;
			lptr = dkgettoken( line, t );
			if( isdigit( t[0] ) )
				line = dkstatement_goto( line );	// got line number following 'then' - goto linenum
			else
				line = dkinterpretline( line );	// got 'then' 
		}
		else if( !strcmp_P( t, PSTR("goto") ) )
			line = dkinterpretline( line ); // got 'goto' 
		else
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_IFWITHOUTTHEN;
			if( elseptr )
				free( thenptr );			// if there's an else clause, memory was allocated for thenptr - free it
			if( e )
				dkexpfree( e );
			return line;					// no 'then' or 'goto' found - syntax error
		}
		lptr=line;
	}
	else
	{										// expression is false, execute ELSE clause
		if( elseptr )
		{
			line = dkinterpretline( elseptr );	// interpret statement after 'else' clause
			lptr=line;			
		}
	}

	if( e )
		dkexpfree( e );

	if( thenptr )
		free( thenptr );			// if memory was allocated for thenptr, free it
	return lptr;
}


//--------------------------------------------------------------------
//--------------------------------------------------------------------
#define DKPRINT_OUTPUT						\
do{	\
	if( !filenum ) \
		printf_P( PSTR("%s"), outline ); \
	else	\
	{		\
		OutFile = dkfilebynum( filenum );	\
		if( !OutFile )	\
		{	\
			if( !dkstatus)	\
				dkstatus = DKSTATUS_BADFILENUMBER;	\
			return line;	\
		}	\
		if( !dkfwrite(outline, strlen(outline), 1, OutFile) )	\
		{	\
			if( !dkstatus)	\
				dkstatus = DKSTATUS_DEVICEIOERROR;	\
			return line;	\
		}	\
	}	\
	outline[0] = '\0';	\
}while(0);
//--------------------------------------------------------------------
char *dkstatement_print( char *line )
{
	dkexpression *e;
	char t[MAX_TOKEN_LENGTH+1];
	uint8_t separator=0;
	uint8_t i;
	char *lptr;
	uint16_t filenum=0;
	char outline[MAX_LINE_LENGTH+1];
	DKFILE *OutFile;
	

	outline[0]='\0';
	outline[MAX_LINE_LENGTH]='\0';

	lptr = dkgettoken( line, t );
	if( t[0]=='#' )						// got PRINT # statement
	{
		line = lptr;
		
		e = expression( line );				// read filenum
		line = expstr;
		dkexptoint( e );
		if( e->type != DKVAR_INTEGER )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}
		filenum = ((int16_t *)e->data)[0];
		if( e )
			dkexpfree( e );

		line = dkgettoken( line, t );	// get , after filenum
		if( t[0] != ',' )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}		
	}

	while( line[0] )
	{
		e = expression( line );
		if( dkstatus != DKSTATUS_OK )
			return expstr;
		if( e )
		{
			if( e->type==DKVAR_INTEGER )
			{	
				lptr = outline;
				if( ((int16_t *)e->data)[0] >= 0 )
				{
					lptr[0]=' ';
					lptr++;
				}
				sprintf_P( lptr, PSTR("%d "), ((int16_t *)e->data)[0] );
				DKPRINT_OUTPUT;
			}
			else if( e->type==DKVAR_BYTE )
			{	
				lptr = outline;
				if( ((int8_t *)e->data)[0] >= 0 )
				{
					lptr[0]=' ';
					lptr++;
				}
				sprintf_P( lptr, PSTR("%d "), ((int8_t *)e->data)[0] );
				DKPRINT_OUTPUT;
			}
			else if( e->type==DKVAR_STRING )
			{
				lptr = ((char **)e->data)[0];
				while( lptr[0] )
				{
					strncpy( outline, lptr, MAX_LINE_LENGTH );
					outline[MAX_LINE_LENGTH]='\0';
					lptr+= strlen( outline );
					DKPRINT_OUTPUT;
				}
			}
			else if( e->type==DKVAR_FLOATSINGLE )
//				sprintf_P( outline, PSTR("%s% 1g "), outline, ((double *)e->data)[0] );
			{	
				sprintf_P( outline, PSTR("% 1g "), ((double *)e->data)[0] );
				DKPRINT_OUTPUT;
			}
			else if( e->type==DKVAR_FLOATDOUBLE )
			{	
				sprintf_P( outline, PSTR("% 1g "), ((double *)e->data)[0] );
				DKPRINT_OUTPUT;
			}
//			else
//			{									// handle default as integer
//				sprintf_P( outline, PSTR("%s%d "), outline, ((int16_t *)e->data)[0] );
//			}
			dkexpfree( e );
		}
		else
		{
			expstr = dkgettoken( line, t );
			if( t[0] == ':' )
				break;							// found ':' statement separator
			else if( t[0] == ',' )
			{									// found ',' separator - advance to next 14-col zone TODO:
				if( ( (dkscreen.width-14) - dkscreen.col ) > 0 )
				{
					for( i = 14-((dkscreen.col-1)%14); i; i-- )
						strcat_P( outline, PSTR(" ") );
//						_putch( ' ' );
				}
				else
					strcat_P( outline, PSTR("\n") );
//					_putch( '\n' );
			}
			else if( t[0] == ';' )
				separator = ';';				// found ';' separator - print next output immediately after last value
			else if( strlen( t ) )
			{
				if( !dkstatus)
					dkstatus = DKSTATUS_SYNTAXERROR;
				return line;
			}
		}
		line = expstr;							// update line with expstr global used by expression()
	}

	if( separator != ';' )
		strcat_P( outline, PSTR("\n") );
	
		
	if( strlen(outline) )
		DKPRINT_OUTPUT
	

	return line;
}


//--------------------------------------------------------------------
char *dkstatement_list( char *line )
{
	struct _dkprogline *programline;
	char *lptr;
	char t[MAX_TOKEN_LENGTH];
	uint16_t startline=0;
	uint16_t endline=0;
	uint8_t gotstartline=0;			
	uint8_t gothyphen=0;
	uint8_t gotendline=0;


	while( line[0] )
	{
		lptr = dkgettoken( line, t );		// get token from line

		if( !t[0] )
			break;

		if( gothyphen )
		{
			if( isdigit( t[0] ) )
			{
				endline = atoi(t);
				line = lptr;
				gotendline = 1;
				break;
			}
			else if( t[0] == '.' )				// '.' = current line (but this doesn't work because dkPC is 0 in interactive mode)
			{
				endline = dkPC;
				line = lptr;
				gotendline = 1;
				break;
			}
			else
				break;
		}
		else if( t[0] == '-' )
		{
			gothyphen = 1;
			line = lptr;
			continue;
		}
		else if( isdigit( t[0] ) )
		{
			startline = atoi(t);
			gotstartline = 1;
			line = lptr;
		}
		else if( t[0] == '.' )					// '.' = current line (but this doesn't work because dkPC is 0 in interactive mode)
		{
			endline = dkPC;
			gotstartline = 1;
			line = lptr;
		}
		else
			break;
	}

	if( gotstartline )
	{
		programline = dkgetclosestprogline( startline );
		if( !programline )
			programline = dkprogram;
		else if( programline->num != startline )
		{
			programline = programline->next;
		}
	}
	else
		programline = dkprogram;			// start at first line

	while( programline )
	{
		printf_P( PSTR("%d %s\n"), programline->num, programline->line );
		programline = programline->next;

		if( gotendline && (programline->num > endline) )	// check if we've reached end of range specified in line
			break;
		if( gotstartline && (!gothyphen) )					// check if we're listing only one line
			break;
	}


	return line;
}
//--------------------------------------------------------------------
char *dkstatement_run( char *line )
{
	dkPC = 0;

	dkrunprogram();


	return line;
}
//--------------------------------------------------------------------
char *dkstatement_stop( char *line )
{
	dkstatus = DKSTATUS_BREAK;

	return line;
}
//--------------------------------------------------------------------
char *dkstatement_cont( char *line )
{
	struct _dkprogline *progline;


	if( dkPC )				// do nothing when executed inside a program
		return line;

	if( !dkprevPC )
		return line;


	progline = dkgetclosestprogline( dkprevPC );

	if( (!progline) || (progline->num != dkprevPC) )
		return line;

	progline = progline->next;
	if(!progline)
		return line;

	dkPC = progline->num;
	dkstatus = DKSTATUS_GOTO;

	return line;
}
//--------------------------------------------------------------------
char *dkstatement_end( char *line )
{
	line = dkstatement_stop( line );

	dkstatus = DKSTATUS_END;


	return line;
}
//--------------------------------------------------------------------
char *dkstatement_goto( char *line )
{
	dkexpression *e;

	e = expression( line );
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					// error: syntax error
	}

	dkPC = ((int16_t *)e->data)[0];
	dkstatus = DKSTATUS_GOTO;

	if( e )
		dkexpfree( e );

	return line;
}
//--------------------------------------------------------------------
char *dkstatement_tron( char *line )
{
	dktrace = 1;

	return line;
}
//--------------------------------------------------------------------
char *dkstatement_troff( char *line )
{
	dktrace = 0;

	return line;
}
//--------------------------------------------------------------------
char *dkstatement_varlist( char *line )
{
	struct _dkvariable *listptr = dkvariables;
	uint8_t i;

	printf_P( PSTR("idx\tname\tvalue\ttype\tnext\tnumdims\tdims[0]\tname\n") );
	for( i=0; listptr; i++ )
	{
		printf_P( PSTR("%d:\t%04X\t%04X\t%04X\t%04X\t%d\t%d\t|%s|\n"), i, listptr->name, listptr->e.data, listptr->e.type, listptr->next, listptr->e.numdimensions, listptr->e.numdimensions ? listptr->e.dimensions[0] : 0, listptr->name );
		listptr = listptr->next;		// point listptr to next item in list
	}


	return line;
}
//--------------------------------------------------------------------
char *dkstatement_save( char *line )
{
	struct _dkprogline *programline;
	char s[MAX_LINE_LENGTH];
	char t[ MAX_TOKEN_LENGTH ];
	DKFILE *programfile;
    dkexpression *e;


	e = expression( line );				// read expression (pinnum)
	line = expstr;
	if( e->type != DKVAR_STRING )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_TYPEMISMATCH;   // should this be type mismatch, or syntax error?
		return line;					
	}
    
    strncpy( t, ((char **)e->data)[0], MAX_TOKEN_LENGTH );	

	programfile = dkfopen( t, "r" );
	if( !programfile )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_FILENOTFOUND;
		return line;					// error
	}	


	programline = dkprogram;			// start at first line

	while( programline )
	{
		sprintf_P( s, PSTR("%d %s\n"), programline->num, programline->line );

		dkfwrite( s, strlen( s ), 1, programfile );

		programline = programline->next;
	}
	
	dkfputc( '\0', programfile );

// if old program was bigger, we should truncate the file to this length?

	dkfclose( programfile );


	return line;
}
//--------------------------------------------------------------------
char *dkstatement_clear( char *line )
{
	dkclearprogram();
	
	return line;
}

//--------------------------------------------------------------------
char *dkstatement_new( char *line )
{
	dknewprogram();


	return line;
}

//--------------------------------------------------------------------
char *dkstatement_load( char *line )
{
    dkexpression *e;    
	char t[ MAX_TOKEN_LENGTH+1 ];


	e = expression( line );				// read expression (pinnum)
	line = expstr;
	if( e->type != DKVAR_STRING )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_TYPEMISMATCH;   // should this be type mismatch, or syntax error?
		return line;					
	}
    
    strncpy( t, ((char **)e->data)[0], MAX_TOKEN_LENGTH );	

	dkstatement_new( NULL );

    if( dkstatus >= DKSTATUS_FIRSTERROR )       // in case an error has been flagged, return now
        return line;
    
	switch( dkloadprogram( t ) )
	{
		case 0:						// success error
			break;

        case 1:                     // file not found - dkstatus == DKSTATUS_FILENOTFOUND so error will be printed by dkerrorhandler()
            break;
			
		case 2:
			printf_P( PSTR("Corrupt data reading file.\n") );
			break;

		case 3:
			printf_P( PSTR("Bad data in file.\n") );
			break;

		case 4:
			printf_P( PSTR("Unexpected end of file or error reading file.\n") );
			break;
	}


	return line;
}
//--------------------------------------------------------------------
char *dkstatement_edit( char *line )
{
	struct _dkexpression *e;
	char t[MAX_TOKEN_LENGTH];
	char *lptr;


	lptr = dkgettoken( line, t );
	if( t[0] == '.' )
	{
		line = lptr;
	}
	else
	{
		e = expression( line );
		line = expstr;
		dkexptoint( e );
		if( e->type != DKVAR_INTEGER )
		{
			dkexpfree( e );
			if( !dkstatus)
				dkstatus = DKSTATUS_TYPEMISMATCH;
			return line;					
		}
	
		dkprevPC = ((int16_t *)e->data)[0];

		if( e )
			dkexpfree( e );
	}

	dkstatus = DKSTATUS_EDIT;


	return line;
}

//--------------------------------------------------------------------
char *dkstatement_for( char *line )
{
	char *lptr;
	char t[MAX_TOKEN_LENGTH+1];
	uint16_t nameflags;
	struct _dkvariable *yvar=NULL;
	void *z;
	struct _dkexpression *e;
	struct _dkfornext *fornextptr = NULL;

										
	line = dkgettoken( line, t );			// gettoken to get variable name
	if( !isalpha( t[0] ) )
	{
		dkstatus = DKSTATUS_SYNTAXERROR;
		return line;
	}

	line = dkgetnameflags( line, &nameflags );
	if(!nameflags)
		nameflags = DKVAR_DEFAULT;

	if( dkfornextstack && dkfornextstack->forlinenum == dkPC )					// if there's something linked to dkfornextstack, check if we're inside this FOR loop
	{
		if( nameflags&DKNAME_INTEGER )
		{									// name specifies integer
			if( (!strcmp( t, dkfornextstack->var->name )) && (dkfornextstack->var->e.type==DKVAR_INTEGER) )
				fornextptr = dkfornextstack; // got match
		}
		else if( nameflags&DKNAME_BYTE )
		{									// name specifies integer
			if( (!strcmp( t, dkfornextstack->var->name )) && (dkfornextstack->var->e.type==DKVAR_BYTE) )
				fornextptr = dkfornextstack; // got match
		}
		else if( nameflags&DKNAME_STRING )
			;
		else if( nameflags&DKNAME_FLOATSINGLE )	// name specifies floatsingle
		{
			if( (!strcmp( t, dkfornextstack->var->name )) && (dkfornextstack->var->e.type==DKVAR_FLOATSINGLE) )
				fornextptr = dkfornextstack; // got match
		}
		else if( nameflags&DKNAME_FLOATDOUBLE )	// name specifies floatdouble
		{
			if( (!strcmp( t, dkfornextstack->var->name )) && (dkfornextstack->var->e.type==DKVAR_FLOATDOUBLE) )
				fornextptr = dkfornextstack; // got match
		}

		if( fornextptr )
		{
			if( fornextptr->var->e.type == DKVAR_INTEGER )
			{
				yvar = dkgetvariable( dkfornextstack->var->name, DKVAR_INTEGER );
				((int16_t *)yvar->e.data)[0] += ((int16_t *)fornextptr->step)[0];
				dksetvariable( dkfornextstack->var->name, DKVAR_INTEGER, yvar->e.data );
			}
			else if( fornextptr->var->e.type == DKVAR_BYTE )
			{
				yvar = dkgetvariable( dkfornextstack->var->name, DKVAR_BYTE );
				((int8_t *)yvar->e.data)[0] += ((int8_t *)fornextptr->step)[0];
				dksetvariable( dkfornextstack->var->name, DKVAR_BYTE, yvar->e.data );
			}
			else if( fornextptr->var->e.type == DKVAR_FLOATSINGLE )
			{
				yvar = dkgetvariable( dkfornextstack->var->name, DKVAR_FLOATSINGLE );
				((double *)yvar->e.data)[0] += ((double *)fornextptr->step)[0];
				dksetvariable( dkfornextstack->var->name, DKVAR_FLOATSINGLE, yvar->e.data );
			}
			else if( fornextptr->var->e.type == DKVAR_FLOATDOUBLE )
			{
				yvar = dkgetvariable( dkfornextstack->var->name, DKVAR_FLOATDOUBLE );
				((double *)yvar->e.data)[0] += ((double *)fornextptr->step)[0];
				dksetvariable( dkfornextstack->var->name, DKVAR_FLOATDOUBLE, yvar->e.data );
			}
		}
	}

	if( !fornextptr )
	{
		yvar = (struct _dkvariable *)malloc( sizeof( struct _dkvariable ) );
		if( !yvar )
		{
			dkstatus = DKSTATUS_OUTOFMEMORY;
			return line;
		}
	
		yvar->name = (char *)malloc( strlen(t)+1 );
		if( !yvar->name )
		{
			free( yvar );
			dkstatus = DKSTATUS_OUTOFMEMORY;
			return line;
		}
	
		strcpy( yvar->name, t );		// fill yvar->name with name (in token)
	
		line = dkgettoken( line, t );	// get next token - should be '='
		if( t[0]!='=' )
		{	
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			free( yvar->name );
			free( yvar );
			return line;
		}
	
		e = expression( line );				// get expression (x)
		line = expstr;
/*
		dkexptoint( e );			// convert expression to integer and store result in y
		if( e->type != DKVAR_INTEGER )
		{									// unable to make an integer from e
			if( !dkstatus)
				dkstatus = DKSTATUS_MISSINGOPERAND;
			free( yvar->name );
			free( yvar );
			return line;
		}
*/

		if( nameflags&DKNAME_INTEGER )
		{
			dkexptoint( e );
			dksetvariable( yvar->name, DKVAR_INTEGER, e->data );
			yvar->e.type = DKVAR_INTEGER;
		}
		else if( nameflags&DKNAME_BYTE )
		{
			dkexptobyte( e );
			dksetvariable( yvar->name, DKVAR_BYTE, e->data );
			yvar->e.type = DKVAR_BYTE;
		}
		else if( nameflags&DKNAME_FLOATSINGLE )
		{
			dkexptofloatsingle( e );
			dksetvariable( yvar->name, DKVAR_FLOATSINGLE, e->data );
			yvar->e.type = DKVAR_FLOATSINGLE;
		}
		else if( nameflags&DKNAME_FLOATDOUBLE )
		{
			dkexptofloatdouble( e );
			dksetvariable( yvar->name, DKVAR_FLOATDOUBLE, e->data );
			yvar->e.type = DKVAR_FLOATDOUBLE;
		}

		dkexpfree(e);
		
		if( dkstatus )
		{
			free( yvar->name );
			free( yvar );
			return line;
		}
	
	
		line = dkgettoken( line, t );	// get next token - should be 'to'
		strlwr( t );
		if( strcmp_P( t, PSTR("to") ) )
		{	
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			free( yvar->name );
			free( yvar );
			return line;
		}
	
		e = expression( line );				// get expression (y)
		line = expstr;

/*		dkexptoint( e );			// convert expression to integer and store result in y
		if( e->type != DKVAR_INTEGER )
		{									// unable to make an integer from e
			if( !dkstatus)
				dkstatus = DKSTATUS_MISSINGOPERAND;
			free( yvar->name );
			free( yvar );
			dkexpfree( e );
			return line;
		}
*/
		if( yvar->e.type == DKVAR_INTEGER )
		{
			yvar->e.data = (int16_t *)malloc(sizeof(int16_t));
			dkexptoint( e );
											// set yvar to ending value (y)
			((int16_t *)yvar->e.data)[0] = ((int16_t *)e->data)[0];
		}
		else if( yvar->e.type == DKVAR_BYTE )
		{
			yvar->e.data = (int8_t *)malloc(sizeof(int8_t));
			dkexptobyte( e );
											// set yvar to ending value (y)
			((int8_t *)yvar->e.data)[0] = ((int8_t *)e->data)[0];
		}
		else if( yvar->e.type == DKVAR_FLOATSINGLE )
		{			
			yvar->e.data = (double *)malloc(sizeof(double));
			dkexptofloatsingle( e );
											// set yvar to ending value (y)
			((double *)yvar->e.data)[0] = ((double *)e->data)[0];
		}
		else if( yvar->e.type == DKVAR_FLOATDOUBLE )
		{
			yvar->e.data = (double *)malloc(sizeof(double));
			dkexptofloatdouble( e );
											// set yvar to ending value (y)
			((double *)yvar->e.data)[0] = ((double *)e->data)[0];
		}
		
		
		dkexpfree( e );

		if( dkstatus )
		{
			free( yvar->name );
			free( yvar );
			return line;
		}
	

	
		z = NULL;									// default step
		lptr = dkgettoken( line, t );		// get next token - check if it is 'step'
		strlwr( t );
		if( !strcmp_P( t, PSTR("step") ) )
		{										// found 'step' keyword	
			line = lptr;
			e = expression( line );				// get expression (z)
			line = expstr;
/*			
			dkexptoint( e );
			if( e->type != DKVAR_INTEGER )
			{
				if( !dkstatus)
					dkstatus = DKSTATUS_MISSINGOPERAND;
				free( yvar->name );
				free( yvar );
				dkexpfree( e );
				return line;
			}
			z = ((int16_t *)e->data)[0];
*/			

			if( yvar->e.type == DKVAR_INTEGER )
			{
				z = (int16_t *)malloc(sizeof(int16_t));
				dkexptoint( e );
				((int16_t *)z)[0] = ((int16_t *)e->data)[0];
			}
			else if( yvar->e.type == DKVAR_BYTE )
			{
				z = (int16_t *)malloc(sizeof(int8_t));
				dkexptobyte( e );
				((int8_t *)z)[0] = ((int8_t *)e->data)[0];
			}
			else if( yvar->e.type == DKVAR_FLOATSINGLE )
			{			
				z = (double *)malloc(sizeof(double));
				dkexptofloatsingle( e );
				((double *)z)[0] = ((double *)e->data)[0];
			}
			else if( yvar->e.type == DKVAR_FLOATDOUBLE )
			{
				z = (double *)malloc(sizeof(double));
				dkexptofloatdouble( e );
				((double *)z)[0] = ((double *)e->data)[0];
			}

			dkexpfree( e );
		}
	
	
	// put yvar and step on fornext pile
		fornextptr = (struct _dkfornext *)malloc( sizeof(struct _dkfornext) );
		if( !fornextptr )
		{
			dkstatus = DKSTATUS_OUTOFMEMORY;
			free( yvar->name );
			free( yvar );
			return line;
		}
	

		if( (!z) && yvar->e.type == DKVAR_INTEGER )
		{
			z = (int16_t *)malloc(sizeof(int16_t));
			((int16_t *)z)[0] = 1;
		}
		else if( (!z) && yvar->e.type == DKVAR_BYTE )
		{
			z = (int8_t *)malloc(sizeof(int8_t));
			((int8_t *)z)[0] = 1;
		}
		else if( (!z) && yvar->e.type == DKVAR_FLOATSINGLE )
		{			
			z = (double *)malloc(sizeof(double));
			((double *)z)[0] = 1;
		}
		else if( (!z) && yvar->e.type == DKVAR_FLOATDOUBLE )
		{
			z = (double *)malloc(sizeof(double));
			((double *)z)[0] = 1;
		}

		fornextptr->step = z;

		fornextptr->var = yvar;
		fornextptr->next = NULL;
		fornextptr->forlinenum = dkPC;
	
		// add fornextptr to dkfornextstack linked list
	
		if( dkfornextstack )
			fornextptr->next = dkfornextstack;
		dkfornextstack = fornextptr;
	}
	else
	{	// increment line to point to end of string or next statement ':'
		do
		{
			lptr = dkgettoken( line, t );
			if( t[0] == ':' )
				break;
			line = lptr;
		} while( t[0] );
	}

	if( !yvar )		// err
		return line;
		
// check fornextptr to see if lines until NEXT should be executed
	if( yvar->e.type == DKVAR_INTEGER )
	{
		yvar = dkgetvariable( fornextptr->var->name, DKVAR_INTEGER );
		if(!yvar)	// err
			return line;
		if( fornextptr->step < 0 )			// negative step
		{
			if( ((int16_t *)yvar->e.data)[0] < ((int16_t *)fornextptr->var->e.data)[0] )
			{
				dkstatus = DKSTATUS_SKIPTONEXT; 	// done loop
			}
		}
		else
		{									// positive step
			if( ((int16_t *)yvar->e.data)[0] > ((int16_t *)fornextptr->var->e.data)[0] )
			{
				dkstatus = DKSTATUS_SKIPTONEXT; 	// done loop
			}
		}
	}
	if( yvar->e.type == DKVAR_BYTE )
	{
		yvar = dkgetvariable( fornextptr->var->name, DKVAR_BYTE );
		if(!yvar)	// err
			return line;
		if( fornextptr->step < 0 )			// negative step
		{
			if( ((int8_t *)yvar->e.data)[0] < ((int8_t *)fornextptr->var->e.data)[0] )
			{
				dkstatus = DKSTATUS_SKIPTONEXT; 	// done loop
			}
		}
		else
		{									// positive step
			if( ((int8_t *)yvar->e.data)[0] > ((int8_t *)fornextptr->var->e.data)[0] )
			{
				dkstatus = DKSTATUS_SKIPTONEXT; 	// done loop
			}
		}
	}
	else if( yvar->e.type == DKVAR_FLOATSINGLE )
	{
		yvar = dkgetvariable( fornextptr->var->name, DKVAR_FLOATSINGLE );
		if(!yvar)	// err
			return line;
		if( fornextptr->step < 0 )			// negative step
		{
			if( ((double *)yvar->e.data)[0] < ((double *)fornextptr->var->e.data)[0] )
			{
				dkstatus = DKSTATUS_SKIPTONEXT; 	// done loop
			}
		}
		else
		{									// positive step
			if( ((double *)yvar->e.data)[0] > ((double *)fornextptr->var->e.data)[0] )
			{
				dkstatus = DKSTATUS_SKIPTONEXT; 	// done loop
			}
		}
	}
	else if( yvar->e.type == DKVAR_FLOATDOUBLE )
	{
		yvar = dkgetvariable( fornextptr->var->name, DKVAR_FLOATDOUBLE );
		if(!yvar)	// err
			return line;
		if( fornextptr->step < 0 )			// negative step
		{
			if( ((double *)yvar->e.data)[0] < ((double *)fornextptr->var->e.data)[0] )
			{
				dkstatus = DKSTATUS_SKIPTONEXT; 	// done loop
			}
		}
		else
		{									// positive step
			if( ((double *)yvar->e.data)[0] > ((double *)fornextptr->var->e.data)[0] )
			{
				dkstatus = DKSTATUS_SKIPTONEXT; 	// done loop
			}
		}
	}


	return line;
}


//--------------------------------------------------------------------
char *dkstatement_next( char *line )
{
	char *lptr;
	char t[MAX_TOKEN_LENGTH+1];
	uint16_t nameflags;


	if( !dkfornextstack )
	{
		dkstatus = DKSTATUS_NEXTWITHOUTFOR;
		return line;
	}
										// gettoken to get variable name
	lptr = dkgettoken( line, t );
	lptr = dkgetnameflags( lptr, &nameflags );
	if(!nameflags)
		nameflags=DKVAR_DEFAULT;

	if( isalpha( t[0] ) )
	{
		if( strcmp( t, dkfornextstack->var->name ) )
		{
			dkstatus = DKSTATUS_NEXTWITHOUTFOR;
			return line;
		}
		line = lptr;
	}


	if( nameflags&DKNAME_INTEGER )
	{									// name specifies integer
		if( dkfornextstack->var->e.type != DKVAR_INTEGER && t[0] )	// name=integer, type!=integer
			dkstatus = DKSTATUS_TYPEMISMATCH;
	}
	else if( nameflags&DKNAME_BYTE )
	{									// name specifies integer
		if( dkfornextstack->var->e.type != DKVAR_BYTE && t[0] )	// name=integer, type!=integer
			dkstatus = DKSTATUS_TYPEMISMATCH;
	}
	else if( nameflags&DKNAME_STRING )
		dkstatus = DKSTATUS_TYPEMISMATCH;	// name specifies string - can't FOR a string!
	else if( nameflags&DKNAME_FLOATSINGLE )	// name specifies floatsingle
	{						
		if( dkfornextstack->var->e.type != DKVAR_FLOATSINGLE && t[0] )	
			dkstatus = DKSTATUS_TYPEMISMATCH;
	}
	else if( nameflags&DKNAME_FLOATDOUBLE )	// name specifies floatdouble
	{						
		if( dkfornextstack->var->e.type != DKVAR_FLOATDOUBLE  && t[0] )	
			dkstatus = DKSTATUS_TYPEMISMATCH;
	}

	if( dkstatus )
		return line;


	dkPC = dkfornextstack->forlinenum; 		// go back to forlinenum
	dkstatus = DKSTATUS_GOTO;


	return line;
}

//--------------------------------------------------------------------
char *dkstatement_while( char *line )
{
	struct _dkexpression *e;
	struct _dkwhilewend *whilewendptr = NULL;

										
	e = expression( line );				// get expression (y)
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_MISSINGOPERAND;
		return line;
	}


	if( dkwhilewendstack && (dkwhilewendstack->whilelinenum == dkPC) )
		;
	else
	{
		whilewendptr = (struct _dkwhilewend *)malloc( sizeof(struct _dkwhilewend) );

		whilewendptr->next = dkwhilewendstack;
		dkwhilewendstack = whilewendptr;	// link new _dkwhilewend into dkwhilnextstack

		dkwhilewendstack->whilelinenum = dkPC;
	}

										// check expression to see if lines until WEND should be executed
										// TODO: check expression type
	if( ! ((uint16_t *)e->data)[0] )	
		dkstatus = DKSTATUS_SKIPTOWEND; 	// done loop

	if( e )
		dkexpfree( e );


	return line;
}


//--------------------------------------------------------------------
char *dkstatement_wend( char *line )
{
	if( !dkwhilewendstack )
	{
		dkstatus = DKSTATUS_WENDWITHOUTWHILE;
		return line;
	}


	dkPC = dkwhilewendstack->whilelinenum; 		// go back to whilelinenum
	dkstatus = DKSTATUS_GOTO;


	return line;
}

//--------------------------------------------------------------------
char *dkstatement_gosub( char *line )
{
	dkexpression *e;
	struct _dkgosub *gosubptr = NULL;


	e = expression( line );
	line = expstr;

	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					// error: syntax error
	}


	if( dkgosubstack && (dkgosubstack->gosublinenum == dkPC) )
		;
	else
	{
		gosubptr = (struct _dkgosub *)malloc( sizeof( struct _dkgosub ) );
		if( !gosubptr )
		{
			dkstatus = DKSTATUS_OUTOFMEMORY;
			return line;
		}
		gosubptr->gosublinenum = dkPC;
		gosubptr->next = dkgosubstack;	// link new struct _dkgosub into list
		dkgosubstack = gosubptr;
	}

	dkPC = ((uint16_t *)e->data)[0];
	dkstatus = DKSTATUS_GOTO;

	if( e )
		dkexpfree( e );


	return line;
}
//--------------------------------------------------------------------
char *dkstatement_return( char *line )
{
	struct _dkgosub *gosubptr;


	if( !dkgosubstack )
	{
		dkstatus = DKSTATUS_RETURNWITHOUTGOSUB;
		return line;
	}

	dkPC = dkgosubstack->gosublinenum; 		// go back to gosublinenum
	gosubptr = dkgosubstack->next;
	free( dkgosubstack );
	dkgosubstack = gosubptr;

	dkstatus = DKSTATUS_RETURN;				// return - start execution at line following dkPC


	return line;
}

//--------------------------------------------------------------------
char *dkstatement_delay( char *line )
{
	struct _dkexpression *e;


	e = expression( line );
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}

//	_delay_ms( ((uint16_t *)e->data)[0] );

	if( e )
		dkexpfree( e );

	return line;
}

//--------------------------------------------------------------------
char *dkstatement_input( char *line )
{
	char s[MAX_LINE_LENGTH+1];
	char t[MAX_TOKEN_LENGTH+1];
	char varname[MAX_TOKEN_LENGTH+1];
	char *lineptr;
	char *sptr;
	char *lptr;
	char *inputprompt=NULL;
	uint8_t separator=0;
	char prompt=0;
	uint16_t nameflags;
	uint16_t value;
	double doublevalue;


	lineptr = line;

// start of input loop
	while( line[0] != ':' )
	{
		line = lineptr;
		lptr = dkgettoken( line, t );
		if( t[0] == ';' )
		{							// got ; before prompt string - don't print newline after <enter> received
			separator = ';';
			line = dkgettoken( lptr, t );
			lptr = line;
		}
		if( t[0] == '\"' )
		{							// got prompt string
			inputprompt = t+1;				// remove leading "
			if( inputprompt[0] )
				inputprompt[ strlen( inputprompt )-1 ] = '\0';	// remove trailing "
	
			printf_P( PSTR("%s"), inputprompt );
		
			line = dkgettoken( lptr, t );
		
			if( t[0] == ';' )
				prompt = ';';
			else if( t[0] == ',' )
				prompt = ',';				// , no ? prompt
			else 							// found a string for input prompt, but no ; or , after
			{		// syntax error
				dkstatus = DKSTATUS_SYNTAXERROR;
				return line;
			}
		}
	
	
		if( prompt != ',' )
			printf_P( PSTR("? ") );		// display ?  prompt
	
			sptr = s;
	
		dkgets( s );					// get string
		if( separator != ';' )
			printf_P( PSTR("\n") );
	
	
		while( line[0] )						// loop through rest of statement line to find variables to read
		{
			lptr = dkgettoken( line, t );
	
			if( t[0] == ':' || t[0] == '\0' )
				break;							// found ':' statement separator
	
			if( !isalpha( t[0] ) )				// check if first character is alpha (could be variable)
				break;
	
			lptr = dkgetnameflags( lptr, &nameflags );
	
			strcpy( varname, t );				// save name from t
	
			sptr = dkgettoken( sptr, t );		// read token from input string
			if( !t[0] )
				break;			// no token in input string - error
	
			if( nameflags&DKNAME_INTEGER )
			{									// name specifies integer
				// read integer from s and store in varname, type int
				if( (!isdigit(t[0])) && (t[0]!='&') )
					break;
				if( t[0]=='&' )
					sptr = dkgettoken( sptr, t+1 );
				
				value = dkstrtonum( t );
				dksetvariable( varname, DKVAR_INTEGER, &value );
			}
			else if( nameflags&DKNAME_STRING )
			{									// name specifies string
				if( t[0] == '\"' )
				{
					t[ strlen(t)-1 ] = '\0';	// remove trailing "
					dksetvariable( varname, DKVAR_STRING, (t+1) );
				}
				else
					dksetvariable( varname, DKVAR_STRING, t );
			}									
			else if( nameflags&DKNAME_FLOATSINGLE )	// name specifies floatsingle
			{									
				if( (!isdigit(t[0])) && (t[0]!='&') )
					break;
				if( t[0]=='&' )
					sptr = dkgettoken( sptr, t+1 );
				doublevalue = dkstrtonum( t );
				dksetvariable( varname, DKVAR_FLOATSINGLE, &doublevalue );
			}
			else if( nameflags&DKNAME_FLOATDOUBLE )	// name specifies floatdouble
			{
				if( (!isdigit(t[0])) && (t[0]!='&') )
					break;
				if( t[0]=='&' )
					sptr = dkgettoken( sptr, t+1 );
				doublevalue = dkstrtonum( t );
				dksetvariable( varname, DKVAR_FLOATDOUBLE, &doublevalue );
			}
			else
			{									// name has no type specifier - default to integer
				// read integer from s and store in varname, type int
				if( (!isdigit(t[0])) && (t[0]!='&') )
					break;
				if( t[0]=='&' )
					sptr = dkgettoken( sptr, t+1 );
				
				value = dkstrtonum( t );
				dksetvariable( varname, DKVAR_INTEGER, &value );
			}
			line = lptr;

			lptr = dkgettoken( line, t );		// get next token (check for , indicating another variable follows)
			if( t[0] == ',' )
			{
				sptr = dkgettoken( sptr, t );	// read , separator from sptr
				if( t[0] == ',' )
				{
					line = lptr;
					continue;
				}
			}
	
			break;
		}
		
		dkgettoken( line, t );				// check if there is another token on the line
		dkgettoken( sptr, s );				// check if there is another token in the input string
		if( (t[0] && t[0]!=':') || s[0] )
		{
			if( dkscreen.col > 1 )
				_putch( '\n' );
			printf_P( PSTR("?Redo from start\n") );			
			continue;						// further items remain on line, redo from start
		}

		break;
	}


	return line;
}


//--------------------------------------------------------------------
char *dkstatement_poke( char *line )
{
	struct _dkexpression *e;
	uint16_t a;
	uint8_t b;
	char t[MAX_TOKEN_LENGTH+1];


	e = expression( line );
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	a = ((uint16_t *)e->data)[0];
	if( e )
		dkexpfree( e );


	line = dkgettoken( line, t );
	if( t[0] != ',' )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	

	e = expression( line );
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	b = ((uint16_t *)e->data)[0];
	if( e )
		dkexpfree( e );


	(*(uint8_t *)a) = b;


	return line;
}

//--------------------------------------------------------------------
/*
// dkstatement_keyled() requires access to keyboard sendcmd()
char *dkstatement_keyled( char *line )
{
	struct _dkexpression *e;
	uint8_t a;


	e = expression( line );
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	a = ((uint16_t *)e->data)[0];
	if( e )
		dkexpfree( e );

#ifdef _DK_USE_KEYBOARD

	dkkeyboard_sendcmd( 0xED );
	dkkeyboard_sendcmd( a );

#endif	// _DK_USE_KEYBOARD

	return line;
}
*/
//--------------------------------------------------------------------

extern char *__malloc_heap_start;
extern char *__malloc_heap_end;

extern char *__brkval;

uint16_t regy;

char *dkstatement_heap( char *line )
{

	printf_P(PSTR("__malloc_heap_start: %X\n__malloc_heap_end: %X\n"),__malloc_heap_start, __malloc_heap_end);
	printf_P(PSTR("__brkval: %X\n"),__brkval);

/*	asm("sts %[regy], r28\n\t"
		"sts %[regy], r29\n\t"
		"\n\t" :
	    [regy] "=r" (regy)  );
*/
	asm("sts regy, r28\n\t"
		"sts regy+1, r29\n\t"
		);

	printf_P(PSTR("Y: %02X%02X\n"),(regy>>8)&0xFF,regy&0xFF);

	return line;
}
//--------------------------------------------------------------------



//--------------------------------------------------------------------
// TODO: implement rest of LOCATE statement
char *dkstatement_locate( char *line )
{
	struct _dkexpression *e;
	uint8_t x;
	uint8_t y;
	char t[MAX_TOKEN_LENGTH+1];


	e = expression( line );				// read row
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	y = ((uint16_t *)e->data)[0];
	if( e )
		dkexpfree( e );

	line = dkgettoken( line, t );
	if( t[0] != ',' )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	

	e = expression( line );				// read col
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	x = ((uint16_t *)e->data)[0];
	if( e )
		dkexpfree( e );

	dkterm_gotoxy( x, y );


	return line;
}

//--------------------------------------------------------------------

char *dkstatement_cls( char *line )
{
	dkterm_clearscreen();

//TODO: check for optional argument (0/1/2)


	return line;
}

//--------------------------------------------------------------------

char *dkstatement_open( char *line )
{
	struct _dkexpression *e;
	uint16_t filenum;
	char filename[FILENAME_MAX];
	char t[MAX_TOKEN_LENGTH+1];
	char *lptr;
	DKFILE *FileHandle;


	e = expression( line );				// read filename
	line = expstr;
	if( e->type != DKVAR_STRING )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}

	strncpy( filename, ((char **)e->data)[0], FILENAME_MAX );

	if( e )
		dkexpfree( e );



	line = dkgettoken( line, t );		// get token from line - AS
	strlwr( t );
	if( strcmp_P( t, PSTR("as") ) )	
	{									// token is not AS
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;
	}


	lptr = dkgettoken( line, t );		// get token from line - if it is # then throw it away
	if( t[0] == '#' )
		line = lptr;
	
	e = expression( line );				// read filenum
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	filenum = ((int16_t *)e->data)[0];
	if( e )
		dkexpfree( e );


	FileHandle = dkfopen( filename, "r+b" );
	if( !FileHandle )
	{				// error - unable to open file
		if( !dkstatus)
			dkstatus = DKSTATUS_DEVICEUNAVAILABLE;
		return line;
	}
	
	FileHandle->filenum = filenum;
	

	return line;
}

//--------------------------------------------------------------------

char *dkstatement_close( char *line )
{
	struct _dkexpression *e;
	uint16_t filenum;
	char t[MAX_TOKEN_LENGTH+1];
	char *lptr;
	DKFILE *FileHandle;
	DKFILE *NextFile;


	lptr = dkgettoken( line, t );		// get token from line - if it is # then throw it away
	if( t[0] == '#' )
		line = lptr;
	
	e = expression( line );				// read filenum
	if( e )
	{
		line = expstr;
		dkexptoint( e );
		if( e->type != DKVAR_INTEGER )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}
		filenum = ((uint16_t *)e->data)[0];
		dkexpfree( e );
	
		FileHandle = dkfilebynum( filenum );
		if( !FileHandle )
		{				// error - unable to open file
			if( !dkstatus)
				dkstatus = DKSTATUS_BADFILENUMBER;
			return line;
		}
		dkfclose( FileHandle );
	}
	else
	{									// CLOSE with no parameters - close all open files
		FileHandle = _dkfile_list;
		while( FileHandle )
		{
			NextFile = FileHandle->next;
			dkfclose( FileHandle );
			FileHandle = NextFile;
		}
	}
	

	return line;
}

//--------------------------------------------------------------------
// ON COM(0) GOSUB 
// setup dkevent_com_handlers[0] with linenum
// TODO: complete ON xxx GOTO / ON xxx GOSUB jump-table functionality
char *dkstatement_on( char *line )
{
	struct _dkexpression *e;
	char t[MAX_TOKEN_LENGTH+1];
	char *lptr;
	uint16_t condition;
	uint16_t param2=0;
	uint8_t action=0;					// 0 = gosub, 1 = goto
	uint8_t setuphandler=0;				// 1 = setting up a COM() event handler, 2 = setting up TIMER()
	uint16_t linenum;
	uint16_t param3=0;
	uint16_t param1=0;
	

// read first token - is it an event name, or is it for a jumptable?
	lptr = dkgettoken( line, t );		// get token from line
	strlwr( t );
	
	if( !strcmp_P( t, PSTR("com") ) )	
	{									// token is COM, setup dkevent_com_handlers[]
		setuphandler = 1;				// indicate that we are setting up COM handler
		
		line = lptr;			
		line = dkgettoken( line, t );		// get '('
		if( t[0] != '(' )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}
		
		e = expression( line );				// read expression (parameter for event handler - com portnum)
		line = expstr;
		dkexptoint( e );
		if( e->type != DKVAR_INTEGER )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}
		
		condition = ((uint16_t *)e->data)[0];
	
		if( e )
			dkexpfree( e );

		line = dkgettoken( line, t );		// get ')'
		if( t[0] != ')' )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;
		}
	}
	else if( !strcmp_P( t, PSTR("timer") ) )	
	{									// token is TIMER, setup dkevent_timer_handlers[]
		setuphandler = 2;				// indicate that we are setting up TIMER handler

		line = lptr;			
		line = dkgettoken( line, t );		// get '('
		if( t[0] != '(' )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}

		e = expression( line );				// read expression (# of timer ticks between timer events)
		line = expstr;
		dkexptoint( e );
		if( e->type != DKVAR_INTEGER )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}
		
		condition = ((uint16_t *)e->data)[0];	

		if( e )
			dkexpfree( e );


		line = dkgettoken( line, t );
		if( t[0] == ',' )
		{									// got a comma, get net parameter
			e = expression( line );				// read expression (timer #)
			line = expstr;
			dkexptoint( e );
			if( e->type != DKVAR_INTEGER )
			{
				if( !dkstatus)
					dkstatus = DKSTATUS_SYNTAXERROR;
				return line;					
			}
			
			param2 = ((uint16_t *)e->data)[0];
	
			if( e )
				dkexpfree( e );
				
			line = dkgettoken( line, t );
		}	


		if( t[0] != ')' || param2 < 0 || param2 > 7)
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;
		}
		

		dktimereventinterval[ param2 ] = condition;
		dktimereventclock[ param2 ] = dktimereventinterval[ param2 ];
	}
	else if( !strcmp_P( t, PSTR("pin") ) )	
	{									// token is PIN, setup dkevent_pin_handlers[]
		setuphandler = 3;				// indicate that we are setting up PIN handler

		line = lptr;			
		line = dkgettoken( line, t );		// get '('
		if( t[0] != '(' )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}

		e = expression( line );				// read expression (PINx address)
		line = expstr;
		dkexptoint( e );
		if( e->type != DKVAR_INTEGER )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}
				
		param1 = ((uint16_t *)e->data)[0];	

		if( e )
			dkexpfree( e );


		line = dkgettoken( line, t );
		if( t[0] != ',' )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}
		
		e = expression( line );				// read expression (pin bit #)
		line = expstr;
		dkexptoint( e );
		if( e->type != DKVAR_INTEGER )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}
		
		param2 = ((uint16_t *)e->data)[0];	

		if( e )
			dkexpfree( e );

		line = dkgettoken( line, t );
		if( t[0] != ',' )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}
		
		e = expression( line );				// read expression (pin value [0=low, 1=high])
		line = expstr;
		dkexptoint( e );
		if( e->type != DKVAR_INTEGER )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}
		
		param3 = ((uint16_t *)e->data)[0];	

		if( e )
			dkexpfree( e );

		
		line = dkgettoken( line, t );
		if( t[0] != ',' )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}
		
		e = expression( line );				// read expression (pin event #)
		line = expstr;
		dkexptoint( e );
		if( e->type != DKVAR_INTEGER )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}
		
		condition = ((uint16_t *)e->data)[0];	

		if( e )
			dkexpfree( e );


		line = dkgettoken( line, t );
		if( t[0] != ')' )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;
		}
		

		if( param2 < 0 || param2 > 7 || param3 < 0 || param3 > 1 || condition<0 || condition>7 )	
		{											// do some sanity-checking of parameters
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;
		}

		dkpins[condition].addr = param1;
		dkpins[condition].bit = param2;
		dkpins[condition].value = param3;
	}
	else
	{
		e = expression( line );				// read expression (condition for jumptable, or parameter for event handler)
		line = expstr;
		dkexptoint( e );
		if( e->type != DKVAR_INTEGER )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}
		
		condition = ((uint16_t *)e->data)[0];
	
		if( e )
			dkexpfree( e );
	}


	line = dkgettoken( line, t );
	strlwr( t );
	if( !strcmp_P( t, PSTR("gosub") ) )	
		action = 0;							// ON x GOSUB linenum
	else if( !strcmp_P( t, PSTR("goto") ) )
		action = 1;							// ON x GOTO linenum
	else
	{									// invalid token
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;
	}



	e = expression( line );				// read linenum
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	
	linenum = ((uint16_t *)e->data)[0];

	if( e )
		dkexpfree( e );


	switch( setuphandler )
	{
		case 3:										// PIN()
			dkevent_pin_handlers[ condition ] = linenum;
			break;


		case 2:										// TIMER()
			dkevent_timer_handlers[ param2 ] = linenum;
			break;


		case 1:										// COM()
			if( condition < 0 || condition > 1 )	// can only handle COM(0) and COM(1)
			{
				if( !dkstatus)
					dkstatus = DKSTATUS_SYNTAXERROR;
				return line;								
			}
			dkevent_com_handlers[ condition ] = linenum;		
			break;


		case 0:										// do jumptable jump
			switch( action )
			{
				case 0:								// gosub
					break;
					
				case 1:								// goto
					break;
			}
			break;
	}	
	
	return line;
}


//--------------------------------------------------------------------
// COM(0) ON
// clear flag in dkeventflags to clear any past event of this type
// set flag in dkeventmasks to enable event
char *dkstatement_com( char *line )
{
	struct _dkexpression *e;
	char t[MAX_TOKEN_LENGTH+1];
	uint16_t portnum;
	

	line = dkgettoken( line, t );		// get '('
	if( t[0] != '(' )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;
	}


	e = expression( line );				// read expression (portnum)
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	
	portnum = ((uint16_t *)e->data)[0];

	if( e )
		dkexpfree( e );


	line = dkgettoken( line, t );		// get ')'
	if( t[0] != ')' )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;
	}

// read first token - is it an event name, or is it for a jumptable?
	line = dkgettoken( line, t );		// get token from line
	strlwr( t );


	if( !strcmp_P( t, PSTR("on") ) )
	{									// COM(x) ON
		switch( portnum )
		{
			case 0:
				dkeventflags &= (~DK_EVENT_COM0);	// clear flag in dkeventflags to clear any past event of this type
				dkeventmasks |= DK_EVENT_COM0;		// set flag in dkeventmasks to enable event
				break;
				
			case 1:
				dkeventflags &= (~DK_EVENT_COM1);
				dkeventmasks |= DK_EVENT_COM1;
				break;
		}
	}
	else if( !strcmp_P( t, PSTR("off") ) )
	{									// COM(x) OFF
		switch( portnum )
		{
			case 0:
				dkeventmasks &= (~DK_EVENT_COM0);	// clear flag in dkeventmasks to disable event
				break;
				
			case 1:
				dkeventmasks &= (~DK_EVENT_COM1);
				break;
		}
	}
	else
	{	
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;
	}


	return line;
}


//--------------------------------------------------------------------
// TIMER ON
// clear flag in dkeventflags to clear any past event of this type
// set flag in dkeventmasks to enable event
char *dkstatement_timer( char *line )
{
	struct _dkexpression *e;
	char t[MAX_TOKEN_LENGTH+1];
	uint16_t timernum=0;


	line = dkgettoken( line, t );		// get first token - could be '(' or command (ON/OFF)
	if( t[0] == '(' )
	{
		e = expression( line );				// read expression (portnum)
		line = expstr;
		dkexptoint( e );
		if( e->type != DKVAR_INTEGER )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}
	
		timernum = ((uint16_t *)e->data)[0];
	
		if( e )
			dkexpfree( e );

		line = dkgettoken( line, t );		// get ')'
		if( t[0] != ')' || timernum<0 || timernum>=NUM_TIMER_HANDLERS )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;
		}

		line = dkgettoken( line, t );		// get token from line
	}

	strlwr( t );


	if( !strcmp_P( t, PSTR("on") ) )
	{									// TIMER ON
		dkeventflags &= (~DK_EVENT_TIMER);	// clear flag in dkeventflags to clear any past event of this type
		dkeventmasks |= DK_EVENT_TIMER;		// set flag in dkeventmasks to enable event

		dktimer_flags &= (~(1<<timernum));
		dktimer_masks |= (1<<timernum);
											// setup timer1
		TCCR1B = 0;							// stop timer1
		TCNT1 = dktimereventtick;	 		// timer overflow every 1 second
		TIMSK1 = (1<<TOIE1);
		TCCR1B = ((1<<CS12) | (0<<CS11) | (1<<CS10));	// start timer at clk/1024			
	}
	else if( !strcmp_P( t, PSTR("off") ) )
	{									// TIMER ON
		dktimer_masks &= (~(1<<timernum));
		if( !dktimer_masks )
			dkeventmasks &= (~DK_EVENT_TIMER);	// clear flag in dkeventmasks to disable event
	}		
	else if( !strcmp_P( t, PSTR("interval") ) )
	{									// TIMER INTERVAL
		e = expression( line );		
		line = expstr;
		dkexptofloatsingle( e );
		if( e->type != DKVAR_FLOATSINGLE )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}

		dktimereventtick = 0x10000 - ( (F_CPU/1024.0) * ((double *)e->data)[0]);

		if( e )
			dkexpfree( e );		
	}
	else
	{	
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;
	}


	return line;
}

//--------------------------------------------------------------------
// PIN ON
// clear flag in dkeventflags to clear any past event of this type
// set flag in dkeventmasks to enable event
char *dkstatement_pin( char *line )
{
	struct _dkexpression *e;
	char t[MAX_TOKEN_LENGTH+1];
	uint16_t pinnum=0;


	line = dkgettoken( line, t );		// get first token - could be '(' or command (ON/OFF)
	if( t[0] == '(' )
	{
		e = expression( line );				// read expression (pinnum)
		line = expstr;
		dkexptoint( e );
		if( e->type != DKVAR_INTEGER )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;					
		}
	
		pinnum = ((uint16_t *)e->data)[0];
	
		if( e )
			dkexpfree( e );

		line = dkgettoken( line, t );		// get ')'
		if( t[0] != ')' || pinnum<0 || pinnum>=NUM_PIN_HANDLERS )
		{
			if( !dkstatus)
				dkstatus = DKSTATUS_SYNTAXERROR;
			return line;
		}

		line = dkgettoken( line, t );		// get token from line
	}

	strlwr( t );


	if( !strcmp_P( t, PSTR("on") ) )
	{									// PIN ON
		if( ((uint8_t *)dkpins[pinnum].addr)[0] & (1<<dkpins[pinnum].bit) )
			dkpins[pinnum].value |= (1<<7);
		else
			dkpins[pinnum].value &= (~(1<<7));

		dkeventflags |= DK_EVENT_PIN;		// set flag in dkeventflags to enable event
		dkeventmasks |= DK_EVENT_PIN;		// set flag in dkeventmasks to enable event

		dkpin_flags &= (~(1<<pinnum));
		dkpin_masks |= (1<<pinnum);
	}
	else if( !strcmp_P( t, PSTR("off") ) )
	{									// PIN OFF
		dkpin_masks &= (~(1<<pinnum));
		if( !dkpin_masks )
			dkeventmasks &= (~DK_EVENT_PIN);	// clear flag in dkeventmasks to disable event
	}		
	else
	{	
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;
	}


	return line;
}

//--------------------------------------------------------------------
char *dkstatement_term( char *line )
{
	struct _dkexpression *e;
	char t[MAX_TOKEN_LENGTH+1];
	int16_t filenum;
	struct _dkterm_interfaces *newinterface;
	

	line = dkgettoken( line, t );		// get '#'
	if( t[0] != '#' )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;
	}


	e = expression( line );				// read expression (filenum)
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	
	filenum = ((int16_t *)e->data)[0];

	dkexpfree( e );


	line = dkgettoken( line, t );		// get token from line
	strlwr( t );


	if( !strcmp_P( t, PSTR("on") ) )
	{									// TERM #x ON
		newinterface = (struct _dkterm_interfaces *)malloc( sizeof( struct _dkterm_interfaces ) );
		newinterface->next = dkterm_interfaces;		// link new _dkterm_interfaces item into list
	
		newinterface->devfile = dkfilebynum( filenum );
		if( newinterface->devfile )
		{
			((struct _dk_ps2kbd *)newinterface->devfile->info)->_flag |= DKPS2KBD_FLAG_TERMINAL;
			newinterface->terminal = &dkterm_vt100;		// indicate that VT100 terminal mode is active
														// should we clear the rx buffer before linking to dkterm_interfaces?
			dkterm_interfaces = newinterface;
		}
		else
			free( newinterface );
	}
	else if( !strcmp_P( t, PSTR("off") ) )
	{									// TERM #x OFF
	}
	else
	{	
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;
	}


	return line;
}


//--------------------------------------------------------------------


//BYTER #1 D@ 3           read from file #1 to D@ (byte array D), 3 bytes
//BYTERW #1 D@ E@ 3     read to D@ send from E@, 3 bytes, file #1
//BYTEW #1 E@ 3          send 3 bytes from E@ to file #1
char *dkstatement_byter( char *line )
{
	struct _dkexpression *e;
	char t[MAX_TOKEN_LENGTH+1];
	int filenum;
	int length;
	uint16_t nameflags;
    char destname[MAX_TOKEN_LENGTH+1];
    DKFILE *InFile;
    unsigned char *data;
    int numdims;
    uint16_t *dims;    


	line = dkgettoken( line, t );       // read '#' before file num
	if( t[0] != '#' )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}


	e = expression( line );				// read filenum
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	
	filenum = ((uint16_t *)e->data)[0];
	if( e )
		dkexpfree( e );

                                        // read variable name
                                        
	line = dkgettoken( line, t );
	
	if( !isalpha( t[0] ) )				// check if first character is alpha (could be variable)
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	strncpy( destname, t, MAX_TOKEN_LENGTH );

	line = dkgetnameflags( line, &nameflags );
    nameflags = DKVAR_BYTE | DKVAR_ARRAY;

	e = expression( line );				// read length
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	
	length = ((uint16_t *)e->data)[0];
	if( e )
		dkexpfree( e );



    if( length < 1 )
        return line;


    InFile = dkfilebynum( filenum );
    if( !InFile )
    {
        if( !dkstatus)
            dkstatus = DKSTATUS_BADFILENUMBER;
        return line;
    }
  
  
  
    data = (unsigned char *)malloc( length );           // allocate space for data (array of bytes)
    if( !data )
	{
		dkstatus = DKSTATUS_OUTOFMEMORY;
		return line;
	}

    numdims = 1;
    dims = (uint16_t *)malloc( 1 * sizeof(uint16_t) );
	dims[0] = length-1;
	
    dkfread( data, length, 1, InFile );                 // read from file into data[]

    dkfillarray( destname, nameflags, data, numdims, dims, length );
    
    free( dims );
    

	return line;
}
//--------------------------------------------------------------------

//BYTER #1 D@ 3           read from file #1 to D@ (byte array D), 3 bytes
//BYTERW #1 D@ E@ 3     read to D@ send from E@, 3 bytes, file #1
//BYTEW #1 E@ 3          send 3 bytes from E@ to file #1
char *dkstatement_bytew( char *line )
{
	struct _dkexpression *e;
	char t[MAX_TOKEN_LENGTH+1];
	int filenum;
	int length;
	uint16_t nameflags;
    DKFILE *OutFile;
    struct _dkvariable *var;


	line = dkgettoken( line, t );       // read '#' before file num
	if( t[0] != '#' )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}


	e = expression( line );				// read filenum
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	
	filenum = ((uint16_t *)e->data)[0];
	if( e )
		dkexpfree( e );

                                        // read variable name
	line = dkgettoken( line, t );
	
    
	line = dkgetnameflags( line, &nameflags );
    nameflags = DKVAR_BYTE | DKVAR_ARRAY;

    var = dkgetvariable( t, nameflags );
    if( !var )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
            

	e = expression( line );				// read length
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	
	length = ((uint16_t *)e->data)[0];
	if( e )
		dkexpfree( e );



    if( length < 1 )
        return line;


    OutFile = dkfilebynum( filenum );
    if( !OutFile )
    {
        if( !dkstatus)
            dkstatus = DKSTATUS_BADFILENUMBER;
        return line;
    }
  
  
  
//    dkfread( data, length, 1, InFile );                 // read from file into data[]
    dkfwrite( var->e.data, length, 1, OutFile );               // write from data[] to file


	return line;
}
//--------------------------------------------------------------------

//BYTER #1 D@ 3           read from file #1 to D@ (byte array D), 3 bytes
//BYTERW #1 D@ E@ 3     read to D@ send from E@, 3 bytes, file #1
//BYTEW #1 E@ 3          send 3 bytes from E@ to file #1
char *dkstatement_byterw( char *line )
{
	struct _dkexpression *e;
	char t[MAX_TOKEN_LENGTH+1];
	int filenum;
	int length;
	uint16_t nameflags;
    char destname[MAX_TOKEN_LENGTH+1];
    DKFILE *InFile;
    unsigned char *data;
    int numdims;
    uint16_t *dims;    
    struct _dkvariable *var;
    int i;


	line = dkgettoken( line, t );       // read '#' before file num
	if( t[0] != '#' )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}


	e = expression( line );				// read filenum
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	
	filenum = ((uint16_t *)e->data)[0];
	if( e )
		dkexpfree( e );

                                        // read variable name (dst)
                                        
	line = dkgettoken( line, t );
	
	if( !isalpha( t[0] ) )				// check if first character is alpha (could be variable)
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	strncpy( destname, t, MAX_TOKEN_LENGTH );

	line = dkgetnameflags( line, &nameflags );
    nameflags = DKVAR_BYTE | DKVAR_ARRAY;


                                        // read variable name (src)
	line = dkgettoken( line, t );
	
	line = dkgetnameflags( line, &nameflags );
    nameflags = DKVAR_BYTE | DKVAR_ARRAY;

    var = dkgetvariable( t, nameflags );
    if( !var )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}


	e = expression( line );				// read length
	line = expstr;
	dkexptoint( e );
	if( e->type != DKVAR_INTEGER )
	{
		if( !dkstatus)
			dkstatus = DKSTATUS_SYNTAXERROR;
		return line;					
	}
	
	length = ((uint16_t *)e->data)[0];
	if( e )
		dkexpfree( e );



    if( length < 1 )
        return line;


    InFile = dkfilebynum( filenum );
    if( !InFile )
    {
        if( !dkstatus)
            dkstatus = DKSTATUS_BADFILENUMBER;
        return line;
    }
  
  
  
    data = (unsigned char *)malloc( length );           // allocate space for data (array of bytes)
    if( !data )
	{
		dkstatus = DKSTATUS_OUTOFMEMORY;
		return line;
	}
	

    numdims = 1;
    dims = (uint16_t *)malloc( 1 * sizeof(uint16_t) );
	dims[0] = length-1;
	


    for( i=0; i<length; i++ )
        data[i] = dkfputc( ((uint8_t *)var->e.data)[i], InFile );
    
    length = i;
	dims[0] = length-1;

    dkfillarray( destname, nameflags, data, numdims, dims, length );
    
    free( dims );


	return line;
}
//--------------------------------------------------------------------
